package com.jinke.api.modules.third.shippo.service.impl;

import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.jinke.api.common.api.CommonResult;
import com.jinke.api.common.exception.Asserts;
import com.jinke.api.common.util.CommonUtil;
import com.jinke.api.common.util.Global;
import com.jinke.api.modules.app.enums.BalanceLogType;
import com.jinke.api.modules.app.enums.OrderStatus;
import com.jinke.api.modules.app.enums.OrderType;
import com.jinke.api.modules.app.enums.ValidateStatus;
import com.jinke.api.modules.app.model.Order;
import com.jinke.api.modules.app.model.OrderParcel;
import com.jinke.api.modules.app.response.CreateLabel2Response;
import com.jinke.api.modules.app.service.IUserOrderTaskService;
import com.jinke.api.modules.app.service.OrderParcelService;
import com.jinke.api.modules.app.service.OrderService;
import com.jinke.api.modules.app.service.UserRechargeService;
import com.jinke.api.modules.app.util.MathUtil;
import com.jinke.api.modules.app.util.OssUtil;
import com.jinke.api.modules.app.util.ParcelUtil;
import com.jinke.api.modules.base.service.ThirdService;
import com.jinke.api.modules.third.ezeeship.model.request.EstimateRateRequest;
import com.jinke.api.modules.third.ezeeship.model.response.CreateLabelResponse;
import com.jinke.api.modules.third.ezeeship.model.response.EstimateRateResponse;
import com.jinke.api.modules.third.ezeeship2.util.EzeeShip2Util;
import com.jinke.api.modules.third.shippo.model.constants.ShippoApiConstants;
import com.jinke.api.modules.third.shippo.model.dto.ShippoRefundReqDTO;
import com.jinke.api.modules.third.shippo.model.response.*;
import com.jinke.api.modules.third.shippo.service.ShippoService;
import com.jinke.api.modules.third.shippo.tool.ShippoRequest;
import com.jinke.api.modules.ums.model.Channel;
import com.jinke.api.modules.ums.model.ChannelCarrier;
import com.jinke.api.modules.ums.model.UmsAdmin;
import com.jinke.api.modules.ums.service.*;
import com.jinke.api.modules.ums.vo.UserChannelVO;
import com.jinke.api.security.util.ApiUserUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @projectName:
 * @title: ShippoServiceImpl
 * @description:
 * @see:
 * @author: hhp
 * @version: 1.0.0
 * @createTime: 2024/8/13 10:12
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ShippoServiceImpl implements ShippoService {
    @Resource
    private   ShippoRequest shippoRequest;
    @Resource
    private  OrderService orderService;
    @Resource
    private  OrderParcelService orderParcelService;
    @Resource
    private  ChannelCarrierService channelCarrierService;
    @Resource
    private EzeeShip2Util ezeeShip2Util;

    @Resource
    private UmsAdminService umsAdminService;
    @Resource
    private UserRechargeService userRechargeService;
    @Resource
    private OssUtil ossUtil;
    @Resource
    private ThirdService thirdService;
    @Resource
    private ChannelService channelService;
    @Resource
    private IApiLogService iApiLogService;
    @Resource
    private IUserOrderTaskService iUserOrderTaskService;


    @Override
    public CommonResult estimateRate(EstimateRateRequest request) {
        Integer userId = ApiUserUtil.getUserId();
        return estimateRate(request, userId);
    }

    @Override
    public CommonResult estimateRate(EstimateRateRequest request, Integer userId) {
        UserChannelVO userChannelVO = request.getUserChannelVO();
        Channel channel = userChannelVO.getChannel();
        //查预估条件
        List<String> getObject_id = getcarrier(channel.getChannelCarrierId());
        EstimateRateResponse.Data newData = new EstimateRateResponse.Data();

        BigDecimal rateAmount;
        try {



            String result = shippoRequest.customsDeclaration(request);

//            String result1 = shippoRequest.declaration(request);

            String shipments = shippoRequest.estimate(request, getObject_id);
            ShippoEstimateVO bean1 = Optional.ofNullable(JSONUtil.toBean(Optional.ofNullable(shipments).orElse(""), ShippoEstimateVO.class))
                    .orElse(new ShippoEstimateVO());
            //先取第一个 返回多个servicelevel和用户渠道对比
            List<ShippoEstimateVO.Rate> rates = bean1.getRates();
            Optional<ShippoEstimateVO.Rate> s = rates.stream().filter(x -> channel.getServiceCode().contains(x.getServicelevel().getName())).findFirst();
            printAllservicelevelBack(rates);
            //如果有
            if (s.isPresent()) {
                ShippoEstimateVO.Rate rate = s.get();
                rateAmount = rate.getAmount();
                newData.setRate(rateAmount);
                //如果有之前不同就更新
                String token = rate.getServicelevel().getToken();
                // if (!channel.getChannelCode().equals(token)         ) {
                channel.setChannelCode(token);
                channelService.updateById(channel);

                //}//
            } else {
                List<ShippoEstimateVO.Message> msg = bean1.getMessages();

                return CommonResult.failed(msg.get(0).getText());

            }
        } catch (Exception e) {
            return CommonResult.failed(e.getMessage());
        }
        if (rateAmount.compareTo(new BigDecimal("0")) == 0) {
            return CommonResult.failed("系统异常请联系管理员");
        }

        return CommonResult.success(newData);


    }

    /**
     * 打印预估返回的所有的serviceLevel
     * @param rates
     */
    private void printAllservicelevelBack(List<ShippoEstimateVO.Rate> rates) {
        List<String> serviceLevelNames = rates.stream()
                .map(rate -> rate.getServicelevel().getName())
                .collect(Collectors.toList());
        System.out.println(serviceLevelNames);

    }

    /**
     * 获取货运商
     *
     * @return
     */
    @NotNull
    private List<String> getcarrier(Integer channelCarrierId) {
        //查货运商
        LambdaQueryWrapper<ChannelCarrier> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ChannelCarrier::getId, channelCarrierId);
        ChannelCarrier one = channelCarrierService.getOne(wrapper);
        List<String> getObject_id = new ArrayList<>();

        switch (one.getChannelCarrierCode()) {
            case "usps":
                getObject_id.add(ShippoApiConstants.usps_token);
                break;
            case "ups":
                getObject_id.add(ShippoApiConstants.ups_us_token);
                break;
            case "fedex":
                getObject_id.add(ShippoApiConstants.fedx_token);
                break;
        }
        return getObject_id;
        // 获取货运商objectId
//        String carrier_accounts = shippoRequest.carrier_accounts();
//        CarrierAcountResponse bean = Optional.ofNullable(JSONUtil.toBean(Optional.ofNullable(carrier_accounts).orElse(""), CarrierAcountResponse.class))
//                .orElse(new CarrierAcountResponse());
//        List<CarrierAcountResponse.Results> results = bean.getResults();
//
//        if (ObjectUtil.isNotNull(results)) {
//            Map<String, String> carrier2ob = results.stream().filter(CarrierAcountResponse.Results::isActive)
//                    .collect(Collectors.toMap(CarrierAcountResponse.Results::getCarrier, CarrierAcountResponse.Results::getObject_id));
//            List<String>  getObject_id = results.stream().filter(CarrierAcountResponse.Results::isActive)
//                    .map(CarrierAcountResponse.Results::getObject_id)
//                    .collect(Collectors.toList());
//
//        }
        //根据channel内容选下面三个中的一个
//
    }

    @Override
    public CommonResult createLabel(EstimateRateRequest request) {
        Integer userId = ApiUserUtil.getUserId();

        return createLabel(request, userId);
    }


    private BigDecimal getPrice(EstimateRateRequest request, Integer userId, UserChannelVO vo) {
        BigDecimal rateAmount;
        CommonResult commonResult = this.estimateRate(request, userId);
        Object data = commonResult.getData();
        EstimateRateResponse.Data tmp;
        if (data instanceof EstimateRateResponse.Data) {
            tmp = (EstimateRateResponse.Data) data;
            BigDecimal rate = tmp.getRate();
            rateAmount = thirdService.calcRate(userId, vo, rate);
        } else {
            throw new RuntimeException(commonResult.getMessage());

        }


        return rateAmount;
    }

    @Override
    public CommonResult createLabel(EstimateRateRequest request, Integer userId) {

        if (StringUtils.isBlank(request.getOrderNO())) {
            request.setOrderNO(CommonUtil.getOrderNo());
        }

        UserChannelVO userChannelVO = request.getUserChannelVO();
        Channel channel = userChannelVO.getChannel();
        request.setServiceCode(channel.getChannelCode());

        // fillResidential(request, userId);
        //估价
        BigDecimal rateAmount;
        try {
            rateAmount = getPrice(request, userId, userChannelVO);
        } catch (Exception e) {
            return CommonResult.failed(e.getMessage());
        }
        UmsAdmin umsAdmin = umsAdminService.getById(userId);
        if (ObjectUtils.isEmpty(umsAdmin) || rateAmount.compareTo(new BigDecimal("0")) <= 0) {
            return CommonResult.failed("系统异常,请联系管理员");
        }
        BigDecimal totalAmount = umsAdmin.getBalance().add(umsAdmin.getCreditBalance());
        if (totalAmount.compareTo(rateAmount) < 0) {
            return CommonResult.failed("Insufficient Balance");
        }
        Integer labelSize = request.getLabelSize();
        if (labelSize == null) {
            request.setLabelSize(1);
        }

        List<String> carrier_accounts = getcarrier(channel.getChannelCarrierId());
        String carrier_accounts1 =carrier_accounts.get(0);
        String strResult = shippoRequest.createLabel(request, carrier_accounts1, channel.getChannelCode());

        if (StringUtils.isNotBlank(strResult)) {
            //保存api下单信息

            Order order = new Order();
            BeanUtils.copyProperties(request, order);
            order.setId(request.getOrderId());
            order.setUserId(userId);
            if (ObjectUtils.isNotEmpty(umsAdmin.getSellerId())) {
                order.setSellerId(umsAdmin.getSellerId());
            }
            ShippoLabelVO createLabelResponse = JSONUtil.toBean(strResult, ShippoLabelVO.class);
            if ("ERROR".equals(createLabelResponse.getStatus())) {
                String errorMessage = createLabelResponse.getMessages().get(0);
                //包涵余额不足提示信息
                if (errorMessage.contains("payment")) {
                    errorMessage = Global.HINT_MSG;
                }
                if (order.getId() != null) {
                    orderService.update(new LambdaUpdateWrapper<Order>().eq(Order::getId, order.getId()).set(Order::getErrMsg, errorMessage));
                }
                return CommonResult.failed(errorMessage);
            }
            order.setOrderNo(request.getOrderNO());
            //设置错误信息为空
            order.setErrMsg("");
            String originFeeStr = createLabelResponse.getRate().getAmount();

            BigDecimal originFee = new BigDecimal(originFeeStr);


            BigDecimal finalRate = thirdService.calcRate(userId, request.getUserChannelVO(), originFee);

            order.setRate(finalRate);

            // 扣钱
            if (finalRate != null && BigDecimal.ZERO.compareTo(finalRate) < 0) {
                userRechargeService.decrTransfer(userId, finalRate, BalanceLogType.CONSUME, "寄件", order.getOrderNo(), order.getObjectId(), channel,null);
            }

            order.setOriginFee(originFee);

            // 上传到oss
            String pdfUrl = createLabelResponse.getLabel_url();
            String objectId = createLabelResponse.getObject_id();
            ossUtil.upload("pdf", objectId + ".pdf", pdfUrl);

            String s = Global.PRINT_LABEL_API;
            String newPdfUrl = s + objectId;
            setorder(request, umsAdmin, order, finalRate, objectId, newPdfUrl);

            orderService.saveOrUpdate(order);
            //定时任务表插入一条数据
            iUserOrderTaskService.saveByOrderId(order.getId());

            Integer orderId = order.getId();

            String trackingNumber = createLabelResponse.getTracking_url_provider();
            String trackingUrl = createLabelResponse.getTracking_number();
            List<EstimateRateRequest.Parcel> parcels = request.getParcels();
            List<OrderParcel> orderParcels = ParcelUtil.getOrderParcels(parcels, orderId, userId);
            //更新包裹信息
            updateParcel( newPdfUrl, orderId, orderParcels,trackingNumber,trackingUrl);

            CreateLabelResponse.Data newCreateLabelResponseData = new CreateLabelResponse.Data();
            newCreateLabelResponseData.setRate(finalRate);

            CreateLabel2Response.FeeDetail newFeeDetail = new CreateLabel2Response.FeeDetail();
            newFeeDetail.setBaseRate(finalRate);
            newCreateLabelResponseData.setFeeDetail(newFeeDetail);

            newCreateLabelResponseData.setRate(finalRate);
            newCreateLabelResponseData.setStatus(1);
            newCreateLabelResponseData.setObjectId(createLabelResponse.getObject_id());
            newCreateLabelResponseData.setPdfUrl(newPdfUrl);
            newCreateLabelResponseData.setTrackingNumber(Arrays.asList(trackingNumber));
            String labelUrl = Global.PRINT_LABEL_API + objectId;
            newCreateLabelResponseData.setLabelUrl(Arrays.asList(labelUrl));

            return CommonResult.success(newCreateLabelResponseData);
        }
        return CommonResult.failed("下单失败请联系管理员");
    }

    /**
     * 更新包裹信息
     * @param newPdfUrl
     * @param orderId
     * @param orderParcels
     * @param trackingNumber
     * @param trackingUrl
     */
    @Transactional
    void updateParcel(String newPdfUrl, Integer orderId, List<OrderParcel> orderParcels, String trackingNumber,
                                String trackingUrl) {

        try {
            for (int j = 0; j < orderParcels.size(); j++) {
                OrderParcel orderParcel = orderParcels.get(j);
                orderParcel.setTrackingNumber(trackingNumber);
                orderParcel.setTrackingUrl(trackingUrl);
                orderParcel.setLabelUrl(newPdfUrl);
            }
        } catch (Exception e) {
            log.error("shippo下单时转包的信息" + e.getMessage());
        }
        // 删除原来的包裹信息
        orderParcelService.remove(new LambdaQueryWrapper<OrderParcel>().eq(OrderParcel::getOrderId, orderId));
        // 入库
        orderParcelService.saveBatch(orderParcels);
    }

    private void setorder(EstimateRateRequest request, UmsAdmin umsAdmin, Order order, BigDecimal finalRate, String objectId, String newPdfUrl) {
        // order.setCreateTime(createLabelResponseData.getCreateTime());

        order.setFromCity(request.getFrom().getCity());
        order.setFromEmail(request.getFrom().getEmail());
        order.setFromCompany(request.getFrom().getCompany());
        order.setFromPhone(request.getFrom().getPhone());
        order.setFromAddressLine2(request.getFrom().getAddressLine2());
        order.setFromAddressLine1(request.getFrom().getAddressLine1());
        order.setFromCountryCode(request.getFrom().getCountryCode());
        order.setFromZipCode(request.getFrom().getZipCode());
        order.setFromPersonName(request.getFrom().getPersonName());
        order.setFromStateCode(request.getFrom().getStateCode());

        order.setReference(request.getExtra().getReference());
        order.setReference2(request.getExtra().getReference2());
        EstimateRateRequest.Address requestTo = request.getTo();
        order.setToCity(requestTo.getCity());
        order.setToEmail(requestTo.getEmail());
        order.setToCompany(requestTo.getCompany());
        order.setToPhone(requestTo.getPhone());
        order.setToAddressLine2(requestTo.getAddressLine2());
        order.setToAddressLine1(requestTo.getAddressLine1());
        order.setToCountryCode(requestTo.getCountryCode());
        order.setToZipCode(requestTo.getZipCode());
        order.setToPersonName(requestTo.getPersonName());
        order.setToStateCode(requestTo.getStateCode());
        order.setOrderType(OrderType.API);


        // todo  保存申明信息
        order.setPdfUrl(newPdfUrl);
        order.setStatus(OrderStatus.RECENT.getValue());
        order.setObjectId(objectId);
        order.setSellerId(umsAdmin.getSellerId());
        order.setChannelId(request.getChannelId());
        order.setCreateTime(LocalDateTime.now());
        if (BooleanUtil.isTrue(requestTo.getIsValid())) {
            order.setValidateStatus(ValidateStatus.defaultEnum(requestTo.getIsResidential()));
        } else {
            order.setValidateStatus(ValidateStatus.UN_VALIDATE);
        }

        BigDecimal earnestRate = umsAdmin.getEarnestRate();
        BigDecimal subEarnestBalance = MathUtil.formatBigDecimal(finalRate.multiply(earnestRate));
        order.setEarnest(subEarnestBalance);

    }

    @Override
    public CommonResult getLabel(String objectId) {
        Integer userId = ApiUserUtil.getUserId();

        return getLabel(objectId, userId);
    }

    @Override
    public CommonResult getLabel(String objectId, Integer userId) {
        CreateLabelResponse.Data labelResult = new CreateLabelResponse.Data();

        Order order = orderService.getOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getObjectId, objectId)
                .eq(Order::getUserId, userId)
        );
        if (order == null) {
            return CommonResult.success(labelResult);
        }
        String pdfUrl = order.getPdfUrl();
        List<OrderParcel> orderParcel = Optional.ofNullable(
                orderParcelService.list(new LambdaQueryWrapper<OrderParcel>()
                        .eq(OrderParcel::getOrderId, order.getId()))
        ).orElse(Lists.newArrayList());

        //查出订单得出物流号trackingNumber
        String trackingNumber = !orderParcel.isEmpty() ? orderParcel.get(0).getTrackingNumber() : null;

        labelResult.setObjectId(objectId);
        labelResult.setRate(order.getRate());
        CreateLabel2Response.FeeDetail newFeeDetail = new CreateLabel2Response.FeeDetail();
        newFeeDetail.setBaseRate(order.getRate());
        labelResult.setFeeDetail(newFeeDetail);
        // labelResult.setStatus(uniPrintPdtResponse.getStatus());
        // labelResult.setCreateTime(createLabelResponseData.getCreateTime());
        // labelResult.setTrackingNumber(trackingNumber);
        List<String> labelList = Lists.newArrayList();

        if (StrUtil.isBlank(pdfUrl)) {
            //如果为空再次查询上传
            String singleLabel = shippoRequest.getSingleLabel(trackingNumber);
            ShippoLabelResponse shippoLabelResponse = Optional.ofNullable(JSONObject.parseObject(Optional.ofNullable(singleLabel).orElse("{}"), ShippoLabelResponse.class)).orElse(new ShippoLabelResponse());
            if (StrUtil.isNotBlank(shippoLabelResponse.getLabelUrl())) {
                labelList.add(shippoLabelResponse.getLabelUrl());
            }
        } else {
            labelList.add(pdfUrl);

        }
        labelResult.setLabelUrl(labelList);

        return CommonResult.success(labelResult);
    }

    @Override
    public CommonResult cancelLabel(String objectId,String orderNo) {
        String msg = "";
        String responseJsonStr = shippoRequest.refund(new ShippoRefundReqDTO().setTransaction(objectId),orderNo);
        ShippoRefundResponse shippoRefundResponse = Optional.ofNullable(JSONObject.parseObject(Optional.ofNullable(responseJsonStr).orElse("{}"), ShippoRefundResponse.class)).orElse(new ShippoRefundResponse());
        String objectStatus = shippoRefundResponse.getObjectStatus();
        if (StrUtil.isNotBlank(objectStatus)) {
            switch (objectStatus) {
                case "QUEUED":
                    // 在取消队列中等待取消
                    log.info("create a refund 排队等待");
                    msg = "排队取消中";
                    break;
                case "PENDING":
                    // 待处理
                    log.info("create a refund 待处理");
                    msg = "处理中";
                    break;
                case "SUCCESS":
                    // 处理完成
                    log.info("create a refund 处理完成");
                    msg = "已取消";
                    break;
                case "ERROR":
                    // 异常
                    log.info("create a refund 失败");
                    Asserts.fail("取消失败，请联系管理员");
                    break;
                default:
                    log.info("create a refund 其他状态:[{}]", objectStatus);
                    break;
            }

            return CommonResult.success(msg);
        }
        return null;
    }

    @Override
    public CommonResult tracking(String trackingNumber) {
        //通过物流号查订单对应的货运商code
        List<OrderParcel> orderParcels = orderParcelService.list(new LambdaQueryWrapper<OrderParcel>()
                .in(OrderParcel::getTrackingNumber, trackingNumber));
        OrderParcel orderParcel = orderParcels.get(0);

        LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<Order>()
                .eq(Order::getId,  orderParcel.getOrderId());

        Order order = orderService.getOne(queryWrapper);
        //查渠道
        Channel channel = channelService.getOne(new LambdaQueryWrapper<Channel>().eq(Channel::getId, order.getChannelId()));

        //查货运商
        LambdaQueryWrapper<ChannelCarrier> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ChannelCarrier::getId, channel.getChannelCarrierId());
        ChannelCarrier carrier = channelCarrierService.getOne(wrapper);

        String trackResult = shippoRequest.getSingleTrack(carrier.getChannelCarrierCode(), trackingNumber);
        ShippoTrackResponse shippoTrackResponse = Optional.ofNullable(JSONObject.parseObject(Optional.ofNullable(trackResult).orElse("{}"), ShippoTrackResponse.class)).orElse(new ShippoTrackResponse());
        ShippoTrackResponse.TrackingHistory trackingStatus = shippoTrackResponse.getTrackingStatus();
        if (ObjectUtil.isNotNull(trackingStatus)) {

        }
        return CommonResult.success(shippoTrackResponse);
    }
    @Override
    public CommonResult cancelInsurance(String insuranceId) {

        return CommonResult.success();
    }
}
